#coding:utf-8
#功能：字典和集合的处理；
import gzip
import math
import os.path
import sys
from os import truncate
from pathlib import Path

import numpy
import numpy as np
import pandas as pd
import torch
from matplotlib import pyplot as plt
from six import iteritems
from sympy import true, false
from torch import tensor, nn
import random
import yaml #pip install PyYAML

from torch.nn import Embedding

def dict_value_length_max_min(r_dict):
    ## 字典{k:{v}}，统计v的最小长度和最大长度
    min_length = min(len(values) for values in r_dict.values())
    max_length = max(len(values) for values in r_dict.values())

    # print("Minimum length:", min_length)
    # print("Maximum length:", max_length)
    return max_length,min_length


def mkdir(dirname):
    """
    功能：创建目录；
    调用：
    mkpath = "data/"
    mkdir(mkpath)
    """
    # 引入模块
    import os
    # 去除首位空格
    dirname = dirname.strip()
    # 去除尾部 \ 符号
    dirname = dirname.rstrip("\\")
    if dirname=="":
        return False
    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    isExists = os.path.exists(dirname)
    # 判断结果
    if not isExists:
        # 如果不存在则创建目录
        # 　  # 创建目录操作函数
        os.makedirs(dirname)
        print(dirname + ' 创建成功')
        return True
    else:
        # 如果目录存在则不创建，并提示目录已存在
        print(dirname + ' 目录已存在,不再重复创建！')
        return False

def mkfile(dirname,filename):
    """
    功能：创建文件-指定目录；
    return:文件对象
    调用：
        dirname="data"#目录名
        filename="dict.txt"#文件名
    """
    # mkdir(dirname)  # 创建目录
    import os
    # 去除首位空格
    dirname = dirname.strip()
    # 去除尾部 \ 符号
    dirname = dirname.rstrip("\\")
    if dirname == "":
        return False
    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    isExists = os.path.exists(dirname)
    # 判断结果
    if not isExists:
        # 如果不存在则创建目录
        # 　  # 创建目录操作函数
        os.makedirs(dirname)
        print(dirname + ' 创建成功')
        return True
    else:
        # 如果目录存在则不创建，并提示目录已存在
        print(dirname + ' 目录已存在,不再重复创建！')

    save_dir = Path(__file__).parent.absolute()  # 当前所在目录
    fdir = os.path.join(save_dir, dirname, filename)  # 连接目录
    file = open(fdir, 'w')
    print(fdir, "创建成功")
    file.close()
    return file


def dict_print(d1):
    """调用：
    d1 = {2:tensor([1,2]),0:3, 1: 5}
    dict_print(d1)
    """
    print(f'dict中key与value首元查看：')
    print_var_len_shape(list(d1.keys())[0])
    print_var_len_shape(list(d1.values())[0])

def list2dict(list1,list2):
    """
    功能：由2个列表生成字典（值列表形式）；
    :param list1: 键列表
    :param list2: 值列表
    :return:
    调用：
    list1=[0,1,2]
    list2=["say hello to","you","world"]
    dlist_str=list2dict(list1,list2)
    print(dlist_str)
    """
    from collections import defaultdict
    if len(list1)!=len(list2):
        return 0
    # dlist = ddict(list)#字典-值列表形式dlist={'train':[(0,0,0),(0,0,1)]}
    dlist_str = defaultdict(list)  # 字典-值列表形式
    for i in range(len(list1)):
        dlist_str[list1[i]].append(list2[i])
    dlist=dict(dlist_str)#{'train': [(0, 0, 0), (0, 0, 1)], 'valid': [(0, 0, 0)], 'test': [(0, 0, 0)]}
    return dlist


def list_triple2txt(listname,dirname,filename,splstr='\t'):
    """
    功能：三元组list->txt（列表三元组或列表存入文本文件）
    输入：[(0,2,3),(1,2,3)]或[0,1,2]
    输出：文本文件（在当前目录下创建）-分行输出-行形式 0    2   3或0
    返回：文件对象
    调用：
    list1=[(0,2,3),(1,2,3)]
    #list1=[1,2,3]
    list2txt(list1,"data/","list3file.txt")
    """
    # 先创建并打开一个文本文件
    # file=mkfile(dirname,filename)
    import os
    # 去除首位空格
    dirname = dirname.strip()
    # 去除尾部 \ 符号
    dirname = dirname.rstrip("\\")
    if dirname == "":
        return False
    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    isExists = os.path.exists(dirname)
    # 判断结果
    if not isExists:
        # 如果不存在则创建目录
        # 　  # 创建目录操作函数
        os.makedirs(dirname)
        print(dirname + ' 创建成功')
        return True
    else:
        # 如果目录存在则不创建，并提示目录已存在
        print(dirname + ' 目录已存在,不再重复创建！')

    save_dir = Path(__file__).parent.absolute()  # 当前所在目录
    fdir = os.path.join(save_dir, dirname, filename)  # 连接目录
    file = open(fdir, 'w')
    print(fdir, "创建成功")

    for i in listname:
        # file.write(i + '\n')#原样写入-行形式(0, 2, 3)
        #实例判断-元素是否可迭代(list or tupel)
        if isinstance(i,list) or isinstance(i,tuple):
            templist = ''
            for j in i:#仅写入元素-行形式0	2	3
                templist+=str(j)+'\t'
                # templist.append(str(j)+splstr)#['0\t', '2\t', '3\t']
            file.write(str(templist) + '\n')
        else:
            file.write(str(i) + '\n')#每个元素分行写入
    # 注意关闭文件
    file.close()
    return file


class Example:

    def __init__(self, head_id, relation, tail_id, **kwargs):#kwargs看作dict
        """
        初始化调用：
        d3= { "head_id": "7246", "head": "焦磷酸钙沉积病[疾病]", "relation": "症状", "tail_id": "750", "tail": "钙化[症状]" }
        Example(**d3)
        特殊（隐式调用）：若kwargs中的键与未知参数相同，则调用时不用显示调用位置参数；
        """
        self.head_id = head_id#数字形式
        self.tail_id = tail_id#数字形式
        self.relation = relation#文本形式

def print_dict_shape(dict1):
    for k, v in dict1.items():
        if type(v) == tuple:
            print(f"k={k},v:len={len(v)},首元={v[0].shape}")
        else:
            print(f"k={k},v:{v.shape}")

def print_dict(batch_dict):
    """
    功能：输出字典所有键值和tensor类型的形状；
    """

    for k, v in batch_dict.items():  #遍历键，值
        print(f"{k}={v}")
        # print("key:", k)
        # if torch.is_tensor(v):#仅输出tensor
        #     print("value:", type(v), v.shape)
    # for k in batch_dict:  # 遍历键
    #     print(k)
    print("--------------------print_dict:finished--------------------\n")


def dict2txt2(dictname,dirname,filename,splstr='\t'):
    """
    功能：dict->txt（字典存入文本文件）
    输出：文本文件（在当前目录下创建）
    返回：文件对象
    注意：返回文件对象可能会影响调用；
    调用：
    dict_temp={'001' : 'a',  '002' : 'b', '003 ': 'c'}
    dirname="data"#目录名
    filename="dict.txt"#文件名
    splstr='\t'#分隔符名
    dict2txt2(dict_temp,dirname,filename,splstr)
    """
    # 先创建并打开一个文本文件
    # file=mkfile(dirname,filename)
    import os
    # 去除首位空格
    dirname = dirname.strip()
    # 去除尾部 \ 符号
    dirname = dirname.rstrip("\\")
    # if dirname == "":
    #     return False
    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    isExists = os.path.exists(dirname)
    # 判断结果
    if not isExists and dirname!='':
        # 如果不存在则创建目录
        # 　  # 创建目录操作函数
        os.makedirs(dirname)
        print(dirname + ' 创建成功')
        return True
    else:
        # 如果目录存在则不创建，并提示目录已存在
        print(dirname + ' 目录已存在,不再重复创建！')

    save_dir = Path(__file__).parent.absolute()  # 当前所在目录
    fdir = os.path.join(save_dir, dirname, filename)  # 连接目录
    with open(fdir, 'w',encoding='utf-8') as file:
        print(fdir, "创建成功")

        # 遍历字典的元素，将每项元素的key和value分拆组成字符串，注意添加分隔符和换行符
        for k, v in dictname.items():
            file.write(str(k) + splstr+ str(v) + '\n')
        print(f"{filename}：生成成功！")
# dict_temp={'001' : 'a',  '002' : 'b', '003 ': 'f'}
# dirname="data"#目录名
# filename="dict.txt"#文件名
# splstr='\t'#分隔符名
# dict2txt(dict_temp,"",filename,splstr)

def dict2txt(dictionary, filename):
    """{k:v}->k:v"""
    with open(filename, 'w',encoding='utf-8') as f:
        for key, value in dictionary.items():
            f.write(f"{key}: {value}\n")
        print(f"{filename}生成成功！")


def txt2dict(filename):
    """注意：字典的键值是冒号分隔的"""
    dictionary = {}
    with open(filename, 'r',encoding='utf-8') as f:
        for line in f:
            line = line.strip()
            key_value = line.split(':')
            key = key_value[0].strip()
            value = eval(key_value[1].strip())
            dictionary[key] = value
    return dictionary



def dict2txt_type(dict_temp,output_file,k_first=True,sep='\t'):
    """功能：将字典写入txt-根据类型；->(key,value)/(value,key)
    优点：没有空的最后一行；
    参数：k_first=True:首列为key；
        k_first=False:首列为value；
    调用：
        dict_temp={'001' : 'a',  '002' : 'b', '003 ': 'f'}
        output_file='dict1.txt'
        dict2txt_type(dict_temp,output_file)
    """
    with open(output_file, 'w',encoding='utf-8') as file:
        # 遍历字典的元素，将每项元素的key和value分拆组成字符串，注意添加分隔符和换行符
        for i,items in enumerate(dict_temp.items()):
            k,v=items
            if k_first:
                file.write(str(k) + sep+ str(v))
                if i != len(dict_temp) - 1:
                    file.write('\n')
            else:
                file.write(str(v) + sep + str(k))
                if i != len(dict_temp) - 1:
                    file.write('\n')

        print(f"{output_file}：生成成功！")
# dict_temp={'001' : 'a',  '002' : 'b', '003 ': 'f'}
# output_file='dict1.txt'
# dict2txt_type(dict_temp,output_file)

def dict2txt2(dict_obj, filename):
    """
    调用：
    my_dict = {'apple': 3, 'banana': 5, 'orange': 2}
    dict2txt2(my_dict, 'my_dict.txt')
    """
    with open(filename, 'w',encoding='utf-8') as f:
        for key, value in dict_obj.items():
            f.write('%s: %s\n' % (str(key), str(value)))
        print(f"{filename}：生成成功！")

def dict_vset(key:str,va:list):
    """
    功能：创建字典值集合（指定键和值列表）；
    调用：
    d4=dict_vset('hell',['1','2'])
    print_dict(d4)
    """
    d1=dict()
    d1[key]=set()#设定指定键的值为空集合
    for i in va:
        d1[key].add(i)
    return d1

def sro2sor(sr2o)->{}:
    """
    功能：由{(s,r):[o1,o2,..]}求{(s,o):r}
    调用：
        sro={(1,2):[3,4,5]}
        print(sro2sor(sro))#{(1, 3): 2, (1, 4): 2, (1, 5): 2}
    """
    sr2o = {k: list(v) for k, v in sr2o.items()}  # 字典列表{(s,r):[o1,o2,..]}
    # print(f"(s,r):[o1,o2,..]:len={len(sr2o)}")
    so2r = {}  # 字典列表{(s,o):[r]}
    for k, o in sr2o.items():
        s = k[0]
        r = k[1]
        for t in o:
            so2r[(s, t)] = r
    # print(f"so2r:len={len(so2r)}")
    return so2r


def dict2DataFrame(count_true:dict,col_key='true',pic_show=true):
    """
    功能：dict->DataFrame,并绘制饼状图；
    输入：{}形如{'qualifier value': 37801, 'body structure': 15998}
    参数：
        col_key='true'  图标题-列名
        pic_show=true   是否绘制饼状图
    饼状图数据形式：
        {'列名':[float数据]},index=[‘行名‘]
        df = pd.DataFrame({'mass': [0.330, 4.87 , 5.97],
            'radius': [2439.7, 6051.8, 6378.1]},index=['Mercury', 'Venus', 'Earth'])
            即一列一个饼图（列值为百分比），index行名-多个标记；
    思路：
        数据行：dict的key作为行名
        数据列：{col_key：dict的values}
    返回：
        df  pd.DataFrame-适合饼状图
        col_value-饼状图的y值-图标题
        indexname-饼状图的行名-图分类字段
    调用1：
        from collections import Counter
        count_true = Counter({'qualifier value': 37801, 'body structure': 15998})
        count_true = dict(count_true.most_common(10))  # Counter取前n项-返回[(键,数量值),]
        df = dict2DataFrame(count_true)
    调用2：

    """
    # count_true=dict(count_true.most_common(5))#Counter取前n项-返回[(键,数量值),]
    # print(count_true)
    from matplotlib import pyplot as plt
    indexname=[]
    col_value=[]
    col_dict={}
    for k,v in count_true.items():
        indexname.append(k)
        col_value.append(v)
    col_dict= {col_key:col_value}
    # print(indexname,type(indexname))
    # print(col_value,type(col_value))
    # print(col_dict,type(col_dict))
    df = pd.DataFrame(col_dict,index=indexname)
    if pic_show:
        plot = df.plot.pie(y=col_key, figsize=(10,10), autopct='%1.0f%%')#绘制饼状图-带占比（百分比）
        plt.show()
    return df,col_value,indexname


def dict_union(d1:dict,d2:dict)->{}:
    """
    功能：字典合并-同键值以后面为准
    调用：
        d1 = {'name': 'revotu', 'age': 99}
        d2 = {'age': 24, 'sex': 'male','school':'ust',}
        print(dict_union(d1,d2))
    """
    d = {**d1, **d2}#全新的字典合并方式
    # d1['name']=set()#设定指定键的值为空集合
    # d1['name'].add('h')
    # d1['name'].add('x')
    # print(d1.get('name'))
    # d = dict(ChainMap(d1, d2)) #通用字典合并方法
    # d = d1.copy() #字典复制
    # d.update(d2)#字典更新
    # print_dict(d1)
    return d


def readDict(filename):
    """指定路径2列文件读为字典{line[0]：line[1]}
    举例：
    dataset_name=''
    file_ent = 'data/{dataset_name}/kg/wd_id2entity_text.txt'.format(
            dataset_name=dataset_name
        )
    e = readDict(file_ent)
    """
    f = open(filename, 'r', encoding='utf-8')
    d = {}
    for line in f:
        line = line.strip().split('\t')
        if len(line) == 1:
            line.append('')  # in case literal was blank or whitespace
        d[line[0]] = line[1]
    f.close()
    return d

def dict_reverse(d1)->{}:
    """功能：字典反转
    调用：
    d1 = {'name': 'revotu', 'age': 99}
    print(dict_reverse(d1))
    """
    d1_rev = {idx: ent for ent, idx in d1.items()}#字典反转
    return d1_rev



def dict_value_2list_table(d1,sample_table_size = 20):
    """功能：词频数{id：word_frequency}->一维np.array
    返回：[0 0 0 0 0 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2]#词频比例有所改变
    调用：
    d1 = {0:3, 1: 5,2:4}
    sample_table=dict_value_2list_table(d1)
    print("sample_table:",sample_table.shape,sample_table)
    """
    sample_table = []
    pow_frequency = numpy.array(list(d1.values())) ** 0.75  # 词频数^0.75
    words_pow = sum(pow_frequency)
    ratio = pow_frequency / words_pow  # 词频率
    count = numpy.round(ratio * sample_table_size)  # 一维
    print("count:", count)
    for wid, c in enumerate(count):
        sample_table += [wid] * int(c)
    sample_table = numpy.array(sample_table)
    return sample_table

def dict_print(d1):
    """调用：
    d1 = {2:tensor([1,2]),0:3, 1: 5}
    dict_print(d1)
    """
    print(f'dict中key与value首元查看：')
    print_var_len_shape(list(d1.keys())[0])
    print_var_len_shape(list(d1.values())[0])


def print_var_len_shape(v):
    """
    功能：变量类型与形状打印
    调用：print_var_len_shape(1)
    """
    if type(v) in [list,dict,tuple,str]:#len()形状类型
        print(f"{type(v)},len={len(v)}")
    elif type(v) in [int,float]:#无len()和shape
        print(f"{type(v)},{v}")
    else:
        print(f"{type(v)},shape={v.shape}")
    return type(v)

# d1 = {2:tensor([1,2]),0:3, 1: 5}

def dict_get_argmax(d1:{})->{}:
    """功能：
    形式：{k:二维tensor}->{k:每行最大值索引}
    调用：
    t1=tensor([[-0.0363, -0.1497,  0.0588,  0.1964, -0.2063]])
    d1={1:t1}
    d2=dict_get_argmax(d1)
    print(d2)
    """
    d2={k:v.argmax(dim=1).item() for k,v in d1.items()}
    return d2

def dict_hit1_acc(pred_index:{}):
    """功能：计算{标签：预测值}的hit@1
    调用：
	hit1, eq_num, n=dict_hit1_acc(run.pred_index)
	print(f"pred_index的hit1：{hit1},{eq_num}/{n}")
    """
    n=len(pred_index)
    eq_num=0
    for k,v in pred_index.items():
        if k==v:
            eq_num+=1
    hit1=eq_num/n
    # print(hit1)
    return hit1,eq_num,n

def dict_hitn_acc(pred_index:{},n=1):
    """功能：计算{标签：[前n预测值]}的hit@n
    调用：
    pred_index={0: [3,2,1], 1:[0,1,2]}
    n=3
    hitn,hitn_num,len=dict_hitn_acc(pred_index,n)
    print(f"pred_index的hit{n}：{hitn},{hitn_num}/{len}")
    """
    l = len(pred_index)
    hitn_num = 0
    for k, v in pred_index.items():
        if k in v[:n]:
            hitn_num += 1
    hitn = hitn_num / l

    return hitn, hitn_num, l


def dict_hitn_acc_list(pred_index:{}):
    """功能：计算{标签：[前n预测值]}的hit@1,3,10
    调用：
    pred_index={0: [3,2,1], 1:[0,1,2]}#->[0.0, 0.5, 0.5],[0, 1, 1]/2
    hitn_list,hitn_num_list,l=dict_hitn_acc_list(pred_index)
    print(f"pred_index的hitn_list：{hitn_list},{hitn_num_list}/{l}")
    """
    l = len(pred_index)
    # hitn_list=[]
    hit1_num = 0
    hit3_num = 0
    hit10_num = 0
    for k, v in pred_index.items():
        if k in v[:1]:
            hit1_num += 1
        if k in v[:3]:
            hit3_num += 1
        if k in v[:10]:
            hit10_num += 1
    hitn_list=[hit1_num / l,hit3_num,hit10_num/l]
    hitn_num_list=[hit1_num,hit3_num,hit10_num]
    return hitn_list,hitn_num_list,l

def dictkv2tensor(d1)->tensor:
    """功能：d1.keys,d1.values()->tensor
    输入要求：{}中为全int或float
    调用：
    d1={1:0,2:1,3:2}
    k1,v1=dictkv2tensor(d1)
    print(k1)#torch.Size([3])
    """
    # d1={1:0,2:1,3:2}
    k1=tensor(list(d1.keys()))
    v1=tensor(list(d1.values()))
    # print(k1,v1)
    return k1,v1


def dictlist_2dict(d1:{})->{}:
    """功能：{k:[v]}->{k:v}  （取values首元）
    调用：
    d1={0: [3,2,1], 1:[0,1,2]}
    d2=dictlist_2dict(d1)
    print(d2)
    """
    d2={}
    for k,v in d1.items():
        d2[k]=v[0]
    # print(d2)
    return d2
# d1={0: [3,2,1], 1:[0,1,2]}
# d2=dictlist_2dict(d1)
# print(d2)

def dictlist_2set(d1:{})->{}:
    """功能：{k:[v]}->{(k,v)}  （展开list中所有元素到集合）
    调用：
        d1={0: [3,2,1], 1:[0,1,2]}
        s1=dictlist_2set(d1)#->{(0, 1), (1, 2), (1, 1), (0, 3), (0, 2), (1, 0)}
        print(s1)
    """
    set1=set()
    for k,v in d1.items():
        for v1 in v:
            set1.add((k,v1))
    # print(d2)
    return set1
# d1={0: [3,2,1], 1:[0,1,2]}
# s1=dictlist_2set(d1)
# print(s1)


def dict_get_all_item_ele(d):
    """取得字典所有元素集合"""
    # d = {(0, 5): [1, 3, 4], (0, 1): [2], (2, 0): [4]}
    s = set()
    for k, v in d.items():
        print(k)
        s.update(k)#注意：字典中添加元组时，会分别添加
        s.update(v)
    # print(s)
    return s


def dictlist_maxlen_index(my_dict):
    """功能：返回字典值列表最大长度和所在键（字典列表最大长度）；
    调用：my_dict = {0: [1, 2], 2: [0, 1, 3,5],3:[0,0,0,0,0,0,0]}
        max_key,max_len=dictlist_maxlen_index(my_dict)#-》3，7
        print(max_key,max_len)
    """
    max_key_len = max({k: len(v) for k, v in my_dict.items()}.items(), key=lambda x: x[1])
    max_key,max_len=max_key_len
    return max_key,max_len
    # return max_key
# my_dict = {0: [1, 2], 2: [0, 1, 3,5],3:[0,0,0,0,0,0,0]}
# max_key,max_len=dictlist_maxlen_index(my_dict)#-》3，7
# print(max_key,max_len)

def dict_reverse(d1):
    """功能：反转字典；"""
    reversed_dict = {value: key for key, value in d1.items()}
    return reversed_dict

def dict_tuple_list_2set(d1:{})->{}:
    """功能：{(s,o):[r]}->{(s,o,r)}  （展开list中所有元素到集合）
    调用：
        d1 = {(0,1): [3, 2, 1], (1,2): [0, 1, 2]}
        s1 = dict_tuple_list_2set(d1)  # ->{(1, 2, 1), (1, 2, 0), (0, 1, 3), (1, 2, 2), (0, 1, 2), (0, 1, 1)}
        print(s1)
    """
    set1=set()
    for k,v in d1.items():
        # print(k,v)
        for v1 in v:
            set1.add(k+(v1,))#元祖中追加单个元素
    # print(d2)
    return set1
# d1 = {(0,1): [3, 2, 1], (1,2): [0, 1, 2]}
# s1 = dict_tuple_list_2set(d1)  # ->{(1, 2, 1), (1, 2, 0), (0, 1, 3), (1, 2, 2), (0, 1, 2), (0, 1, 1)}
# # print(s1)

def dict_tuple_list2set_res_value1(d1):
    """功能：值中有1仅保留1，不含1的不变
    形式：{(0,1): [1,0], (1,2): [0],(1,3): [4,5]}-》{(1, 3, 5), (1, 2, 0), (1, 3, 4), (0, 1, 1)}
    调用：
        d1 = {(0,1): [1,0], (1,2): [0],(1,3): [4,5]}
        s1=dict_tuple_list2set_res_value1(d1)
        print(s1)
    """
    # d1 = {(0,1): [1,0], (1,2): [0],(1,3): [4,5]}
    set1=set()
    for k,v in d1.items():
        # print(k,v)
        v=[1] if 1 in v else v
        for v1 in v:
            set1.add(k+(v1,))#元祖中追加单个元素
    return set1
# d1 = {(0,1): [1,0], (1,2): [0],(1,3): [4,5]}
# s1=dict_tuple_list2set_res_value1(d1)
# print(s1)


def set_tuple_list2txt(outfile,sep='\t'):
    """功能：将{()}写入txt文件；
    调用：
        s1={(1, 2, 1), (1, 2, 0), (0, 1, 3), (1, 2, 2), (0, 1, 2), (0, 1, 1)}
        set_tuple_list2txt("data/result1.txt")
    """
    with open(outfile,'w',encoding='utf-8') as f:
        for d in s1:
            s=sep.join([str(i) for i in d])#int型tuple转换->str
            f.write(s+'\n')
    print(f"{outfile}:生成成功！")
# s1={(1, 2, 1), (1, 2, 0), (0, 1, 3), (1, 2, 2), (0, 1, 2), (0, 1, 1)}
# set_tuple_list2txt("data/result1.txt")


def dict_update_by_dict2(dict1, dict2):
    """根据dict2更新dict1
    调用：
    d1={1:0,2:1,3:2}
    d2={5:4}
    print(dict_update_by_dict2(d1,d2))"""
    d=dict1.copy()
    for key in dict2.keys():
        if key not in dict1.keys() or isinstance(dict2[key], str) or isinstance(dict2[key], bool) or isinstance(dict2[key], int):
            d[key] = dict2[key]
        # else:
        #     deep_update_config(dict1[key], dict2[key])
    return d


def dict_get_kv_by_index(d1,i=0):
    """
    功能：dict由索引取kv
    调用：
    d1={1:0,2:1,3:2}
    k,v=dict_get_kv_by_index(d1,i=2)
    print(k,v)
    """
    if i>=len(d1):
        return
    k=list(d1.keys())[i]
    v=list(d1.values())[i]
    return k,v


def dictlist_getvbydict(d1:{},d2:{})->{}:
    """功能：d1中均为key，从d2中取value
    形式：{k:[v]},{k:m}->{m:[m]}
    调用：
    d1={0: [3,2,1], 1:[0,1,2]}
    d2= {0:'a',1:'b',2:'c',3:'ad'}
    print(dictlist_getvbydict(d1,d2))
    """
    d={}
    for k,v in d1.items():
        temp=[d2[i] for i in v]
        d[d2[k]]=temp
    return d


def dictlist_2tensor(d1:{})->tensor:
    """功能：{k:[v]}->v的tensor （取values首元）
    用途：v为一维list适用；
    调用：
    d1={0: [3,2,1], 1:[0,1,2]}
    d2=dictlist_2dict(d1)
    print(d2)
    """
    d2=d1.values()#dict->dict_values
    d2 =tensor(list(d2))
    # print(d2)
    return d2


def dictensor2tensor(d1)->tensor:
    """功能：返回values的tensor
    升维形式{k:tensor(m,n)}->tensor(len(d1),m,n) 或者 {k:tensor(m)}->(len(d1),m)
    ValueError: only one element tensors can be converted to Python scalars
    原因：要转换的list里面的元素包含多维的tensor
    调用：
    # t1=tensor([-0.0363, -0.1497,  0.0588,  0.1964, -0.2063])
    t1=tensor([[-0.0363, -0.1497,  0.0588,  0.1964, -0.2063]])#torch.Size([1, 5])
    d1={1:t1,2:t1}
    print(dictensor2tensor(d1).shape)#torch.Size([1, 5])->(2,5)
    """
    l=[]
    for k,v in d1.items():
        vshape=len(v.shape)#值维度1/2
        v=v.squeeze().tolist()
        # v = v.tolist()
        l.append(v)
    t=tensor(l)
    if len(t.shape)==2 and vshape==2:
        t=t.unsqueeze(1)
    # print(t)
    return t


def read_word_vecs(filename):
    """功能：文件名输入应为data.emb300_final->{词:一维词权重array}
    filename中；'w w词的嵌入权重str'
    """
    wordVectors = {}
    if filename.endswith('.gz'):
        fileObject = gzip.open(filename, 'r')
    else:
        fileObject = open(filename, 'r', encoding="utf-8")

    for line in fileObject:
        line = line.strip().lower()
        word = line.split()[0]

        try:
            vec = numpy.array(line.split()[1:], dtype=numpy.float64)
        except:
            continue

        wordVectors[word] = numpy.zeros(len(line.split()) - 1, dtype=numpy.float64)
        # for index, vecVal in enumerate(line.split()[1:]):
        #   # wordVectors[word][index] = float(vecVal)

        wordVectors[word] = vec

        ''' normalize weight vector '''
        wordVectors[word] /= math.sqrt((wordVectors[word] ** 2).sum() + 1e-6)

    sys.stderr.write("Vectors read from: " + filename + " \n")
    return wordVectors


def dict2nn_embedding(newWordVecs:{}):
    """
    形式：{词：一维array}->二维FloatTensor->nn.Embedding
    调用：
        embedding=txt_dict2nn_embedding(worvecsFileName)
    """
    # 1. {}->二维FloatTensor
    newWordVecs_tensor=dictensor2tensor(newWordVecs)#{}->二维tensor,torch.Size([21128, 768])
    # print_var_len_shape(newWordVecs_tensor)
    #2. 二维FloatTensor->nn.Embedding
    embedding = nn.Embedding.from_pretrained(newWordVecs_tensor)#-><class 'torch.nn.modules.sparse.Embedding'>
    # print_var_len_shape(embedding)
    return embedding


def embdding_print(emb):
    import torch.nn as nn

    # # 创建一个embedding层
    # emb = nn.Embedding(5, 3)
    # 打印embedding层的形状
    print("emb.weight.shape:",emb.weight.shape)
    print("emb.weight.data:", emb.weight.data)


def emb_highest_dim_zero(vocab_size,embed_size):
    """功能：创建一个Embedding，并将emb的最高维度数据置0；->Embedding(vocab_size,embed_size)
    调用：
        emb=emb_highest_dim_zero(5,3)
        print(emb(torch.LongTensor([4])))
    """
    import torch.nn as nn
    import torch

    # 创建一个embedding层
    emb = nn.Embedding(vocab_size, embed_size)

    # 将索引为4的embedding向量的最高维度设置为0
    emb.weight.data[vocab_size-1].zero_()#emb.weight.data.zero_()#所有数据均置0

    # 查看emb矩阵
    input_indices = torch.LongTensor(range(vocab_size))
    embedded = emb(input_indices)
    # print(embedded)
    return emb
# emb=emb_highest_dim_zero(5,3)
# print(emb(torch.LongTensor([4])),emb.weight.shape)


def dict_vlist2Embedding(d1,vocab_size,embed_size):
    """功能：字典键的自适应嵌入（结合值列表）；k嵌入=k嵌入+value嵌入；
    注意：embedding()调用时: 索引 must be Tensor, not int
    返回：tensor(len(dict),embed_size)
    调用：
        d1={0: [1, 2], 1: [2, 3,0],3:[0]}
        embeddings=dict_vlist2Embedding(d1,4,5)
        print(embeddings)
    """
    # d1={0: [1, 2], 1: [2, 3,0],3:[0]}
    emb=nn.Embedding(vocab_size,embed_size)#emb=emb_highest_dim_zero(vocab_size+1,embed_size)#增加最高维，并置0
    # # 生成包含所有索引的张量
    # indices = torch.arange(4)
    # # 将索引张量传递给嵌入层，获取所有嵌入向量
    # embeddings = emb(indices)
    # 定义一个空列表用于保存所有的嵌入向量
    embeddings = []

    # 循环遍历字典 d1
    for k, v in d1.items():
        # 获取自身的嵌入向量
        emb_k = emb(torch.tensor([k]))
        # 获取值列表中索引所对应的嵌入向量
        emb_v = emb(torch.tensor(v))
        # 将自身嵌入向量和值列表中索引所对应的嵌入向量相加
        emb_kv = torch.sum(torch.cat([emb_k, emb_v], dim=0), dim=0)
        # 将嵌入向量添加到列表中
        embeddings.append(emb_kv)

    # 将所有嵌入向量拼接为一个张量
    embeddings = torch.stack(embeddings)

    return embeddings
# d1={0: [1, 2], 1: [2, 3,0],3:[0]}
# embeddings=dict_vlist2Embedding(d1,4,5)
# print(embeddings)


def dict_comple_bykey(d1,vocab_size,comple_value):
    """功能：（1）按总索引补全字典键，补全值为comple_value；（2）补全后字典长度=total_index
    调用：
        d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
        print(dict_comple_bykey(d1,4,[-1]))#-》{0: [1, 2], 1: [2, 3, 0], 3: [0], 2: [-1]}
    """
    # d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
    # total_index = 4

    # 补全索引键
    for i in range(vocab_size):
        if i not in d1:
            d1[i] = comple_value

    # print(d1)  # 输出补全后的字典
    return d1


def dict_all_items(my_dict):
    """功能： 求dict的键值中包含的所有元素，不要重复元素；返回:[]
    方法：使用 set 和列表推导式获取所有元素，去重之后转为列表
    my_dict = {0: [1, 2], 2: [0, 1, 3]}
    """
    all_keys = set([item for item in my_dict.keys()])
    # print(all_keys)
    all_value = set([item for sublist in my_dict.values() for item in sublist])
    # # 计算所有值列表的最大长度
    # v_max_len = max([len(v) for v in my_dict.values()])
    all_items=list(all_keys|all_value)# & 和 | 运算符，分别表示取交集和并集
    # 输出结果
    # print(all_items)
    return all_items

def dict_vlist2tensor(d):
    """功能：给定一个{0: [1, 2, 4], 2: [0, 1, 3], 1: [4, 4, 4], 3: [4, 4, 4]}，将其按key的升序存放为一个二维张量；"""
    import numpy as np

    # 给定字典
    # d = {0: [1, 2, 4], 2: [0, 1, 3], 1: [4, 4, 4], 3: [4, 4, 4]}

    # 按key的升序排序
    d_sorted = sorted(d.items())
    # 转换为二维张量
    tensor1 = np.array([v for k, v in d_sorted])
    # print(tensor1)
    return tensor1


def dict_complet_bykey_value(origin_dict):
    """功能：补全字典的键和值，返回有序张量；
    优点：补全字典到len()=vocab_size,值列表=最长（补全值为[vocab_size]）；
    返回：
        （1）my_dict:无序,     （2）tensor_order(2,n)（vocab_size,值列表长度）
    调用：
        my_dict = {0: [1, 2], 2: [0, 1, 3]}
        my_dict,tensor_order=dict_complet_bykey_value(my_dict)
        print(my_dict,'\n',tensor_order)
    """
    # my_dict = {0: [1, 2], 2: [0, 1, 3]}
    my_dict=origin_dict.copy()
    #取字典所有元素-求长度
    all_items=list(set([item for item in my_dict.keys()])|set([item for sublist in my_dict.values() for item in sublist]))
    vocab_size=len(all_items)
    complet_value=[vocab_size]
    #（1）补全字典键（按索引补全，补全值为[vocab_size]）(字典多了个元素)
    # my_dict=dict_comple_bykey(my_dict,vocab_size,complet_value)
    for i in range(vocab_size):
        if i not in my_dict:
            my_dict[i] = complet_value
    # print(my_dict)
    #(2)字典值列表补全到最大长度（补全值为vocal_size）
    # 计算所有值列表的最大长度
    max_len = max([len(v) for v in my_dict.values()])
    # 将所有值列表的长度补到相等长度
    for k, v in my_dict.items():
        my_dict[k] = v + complet_value* (max_len - len(v))
    # 输出结果
    # print(my_dict)

    # 按key的升序排序
    my_dict_sorted = sorted(my_dict.items())
    # 转换为二维张量
    tensor_order = np.array([v for k, v in my_dict_sorted])

    return my_dict,tensor_order
# my_dict = {0: [1, 2], 2: [0, 1, 3]}
# my_dict,tensor_order=dict_complet_bykey_value(my_dict)
# print(my_dict,'\n',tensor_order)


def dict_complet_bykey_value_label01(orgin_dict,vocab_size,max_len):
    """功能：(1)补全字典的键和值（补全值为vocab_size]），返回有序张量；(2)补全键处标签置0，未补全键处标签置1；
    优点：补全字典到len()=vocab_size,值列表长度=max_len（补全值为[vocab_size]）；
    返回：
        （1）my_dict:补全后的字典-无序,     （2）tensor_order(2,n)（vocab_size,值列表长度）
        (3)labels:标签（1/0），1-表示键不是补全来的，0表示键是补全来的；
    调用：
        orgin_dict = {0: [1, 2], 2: [0, 1, 3]}
        my_dict,tensor_order,labels=dict_complet_bykey_value_label01(orgin_dict,4,4)
        print(my_dict,'\n',tensor_order,'\n',labels)
    """
    # orgin_dict = {0: [1, 2], 2: [0, 1, 3]}
    my_dict=orgin_dict.copy()#补全后的字典-无序
    #取字典所有元素-求长度
    all_items=list(set([item for item in my_dict.keys()])|set([item for sublist in my_dict.values() for item in sublist]))
    orign_vocab_size=len(all_items)
    complet_value=[vocab_size]
    #（1）补全字典键（按索引补全，补全值为[vocab_size]）(字典多了个元素)
    # my_dict=dict_comple_bykey(my_dict,vocab_size,complet_value)

    for i in range(vocab_size):
        if i not in my_dict:
            my_dict[i] = complet_value
    # print(my_dict)
    #(2)字典值列表补全到最大长度（补全值为vocal_size）
    # 计算所有值列表的最大长度
    # origin_max_len = max([len(v) for v in my_dict.values()])
    max_key, origin_max_len = max({k: len(v) for k, v in my_dict.items()}.items(), key=lambda x: x[1])
    print(f"原始字典self.vocab_size={orign_vocab_size}，值列表最大长度={origin_max_len},所在key={max_key}")
    # print(f"原始字典vocab_size={orign_vocab_size}，值列表最大长度={origin_max_len}")
    print(f"补全后字典vocab_size={vocab_size}，值列表最大长度={max_len}")
    # 将所有值列表的长度补到相等长度
    for k, v in my_dict.items():
        my_dict[k] = v + complet_value* (max_len - len(v))
    # 输出结果
    # print(my_dict)

    # 按key的升序排序
    my_dict_sorted = sorted(my_dict.items())
    # 转换为二维张量
    tensor_order = torch.tensor(np.array([v for k, v in my_dict_sorted]))
    # 判断每一行是否全为vocab_size
    is_all_four = torch.all(tensor_order == vocab_size, dim=1)
    # print(is_all_four)
    # 创建一个相应长度的一维张量
    labels = torch.zeros(tensor_order.size(0), dtype=torch.int)

    # 如果某行全为 4，则对应的一维张量值为 0；否则为 1
    labels[~is_all_four] = 1
    return my_dict,tensor_order,labels
# orgin_dict = {0: [1, 2], 2: [0, 1, 3]}
# my_dict,tensor_order,labels=dict_complet_bykey_value_label01(orgin_dict,4,4)
# print(my_dict,'\n',tensor_order,'\n',labels)


def dgl2dict_tlist(g):
    """功能：由dgl图取字典-src_node,rel_type相同的所有尾结点列表->{’s_rel‘:[尾结点列表]}
    形式：
    参数：g:dgl图；
    返回：
        （1）h_r_tlist_dict（尾结点列表）：{'0_0': [1, 3, 4], '0_1': [2], '2_0': [4]}
        （2）s_r_str_set ('头_关系'集合):{'2_0', '0_1', '0_0'}
    调用：
        # 创建有向图
        src_list = [0, 0, 0, 0, 2]
        dst_list = [1, 2, 3, 4, 4]
        rel_list = [0, 1, 0, 0, 0]
        g = dgl.graph((src_list, dst_list))
        g.edata['rel_type'] = torch.tensor(rel_list)
        #
        h_r_tlist_dict=dgl2dict_tlist(g,0,0)# -》 {'0_0': [1, 3, 4], '0_1': [2], '2_0': [4]}
    """
    edges=g.edges()
    src_nodes = edges[0]
    des_nodes=edges[1]
    edges_type=g.edata['rel_type']#取边类型->tensor([0, 1, 0, 0, 0])
    # print(edges_type)
    # print(src_nodes,des_nodes)

    # 指定查询的起点和边类型的终点列表，放入字典中；
    h_r_tlist_dict={}
    s_r_str_set=set()
    for src_node,rel_type in zip(src_nodes.tolist(),edges_type.tolist()):
        s_r_str=str(src_node)+'_'+str(rel_type)
        s_r_str_set.add(s_r_str)
        # print(s_r_str_set)
        # 使用边类型和源节点过滤边
        eids = g.filter_edges(lambda edges: (src_nodes == src_node) & (edges_type == rel_type))
        # print(eids)
        # 获取边的目标节点
        dst_nodes = g.find_edges(eids)[1]

        # 去重
        unique_dst_nodes = torch.unique(dst_nodes)
        # 将结果添加到字典中
        h_r_tlist_dict[f"{src_node}_{rel_type}"] = unique_dst_nodes.tolist()
    return h_r_tlist_dict,s_r_str_set


def dgl2dict_tuple_list(g):
    """功能：由dgl图取字典-src_node,rel_type相同的所有尾结点列表->{(s,rel):[尾结点列表]} \n
    形式： \n
    参数：g:dgl图； \n
    返回： \n
        （1）h_r_tlist_dict（尾结点列表）：{(0,0): [1, 3, 4], (0,1): [2], (2,0): [4]} \n
        （2）s_r_str_set (键集合) ('头_关系'集合):{(2,0), (0,1), (0,0)} \n
    调用： \n
        import dgl
        # 创建有向图
        src_list = [0, 0, 0, 0, 2]
        dst_list = [1, 2, 3, 4, 4]
        rel_list = [0, 1, 0, 0, 0]
        g = dgl.graph((src_list, dst_list))
        g.edata['rel_type'] = torch.tensor(rel_list)
        h_r_tlist_dict,key_set=dgl2dict_tuple_list(g)
        print(h_r_tlist_dict,s_r_str_set)
        for k,v in h_r_tlist_dict.items():
            print(k,v)
    """
    edges=g.edges()
    src_nodes = edges[0]
    des_nodes=edges[1]
    edges_type=g.edata['rel_type']#取边类型->tensor([0, 1, 0, 0, 0])
    # print(edges_type)
    # print(src_nodes,des_nodes)

    # 指定查询的起点和边类型的终点列表，放入字典中；
    h_r_tlist_dict={}
    s_r_str_set=set()
    for src_node,rel_type in zip(src_nodes.tolist(),edges_type.tolist()):
        # s_r_str=str(src_node)+'_'+str(rel_type)
        s_r_str_set.add((src_node,rel_type))
        # print(s_r_str_set)
        # 使用边类型和源节点过滤边
        eids = g.filter_edges(lambda edges: (src_nodes == src_node) & (edges_type == rel_type))
        # print(eids)
        # 获取边的目标节点
        dst_nodes = g.find_edges(eids)[1]

        # 去重
        unique_dst_nodes = torch.unique(dst_nodes)
        # 将结果添加到字典中
        h_r_tlist_dict[(src_node,rel_type)] = unique_dst_nodes.tolist()
    return h_r_tlist_dict,s_r_str_set


def dict_tuple_list_complet_bykey_value(orgin_dict,kset,vocab_size,max_len):
    """功能：补全{（s,r）:[o]} \n
    特点：(1)补全字典的键和值（补全值为vocab_size]） \n
    形式：{（s,r）:[]} -> 补全的{(s,r)):[]}； \n
    参数：orgin_dict：{(0, 0): [1, 3, 4], (0, 1): [2]}, \n
        kset：全部键集合, \n
        h_tensor：头张量, \n
        r_tensor：关系张量, \n
        vocab_size：词汇长度,  max_len：最大列表长度， \n
    补全如：{(0, 0): [1, 3, 4], (0, 1): [2], (2, 0): [4]}； \n
        ->  {(0, 0): [1, 3, 4], (0, 1): [2, 5, 5], (2, 0): [4, 5, 5]}； \n
    优点：补全字典到len()=vocab_size,值列表长度=max_len（补全值为[vocab_size]）；； \n
    返回：； \n
        （1）my_dict:补全后的字典-无序,     ； \n
        （2）value_tensor (以(h,r)为键，在my_dict中的取值)：（len(h_tensor),max_len）； \n
        #(3)labels:标签（1/0），1-表示键不是补全来的，0表示键是补全来的； \n
    调用： \n
        import dgl
        # 创建有向图
        src_list = [0, 0, 0, 0, 2]
        dst_list = [1, 2, 3, 4, 4]
        rel_list = [0, 1, 0, 0, 0]
        g = dgl.graph((src_list, dst_list))
        g.edata['rel_type'] = torch.tensor(rel_list)
        h_r_tlist_dict,key_set=dgl2dict_tuple_list(g)#->{(0, 0): [1, 3, 4], (0, 1): [2], (2, 0): [4]} \t {(0, 1), (2, 0), (0, 0)}
        # orgin_dict = {(0, 0): [1, 3, 4], (0, 1): [2]}#, (2, 0): [4]
        # s_r_str_set = {(0, 1), (2, 0), (0, 0)}
        comp_dict=dict_tuple_list_complet_bykey_value(h_r_tlist_dict,key_set,vocab_size=5,max_len=3)
        print(comp_dict)
    """
    # orgin_dict = {'0_0': [1, 3, 4], '0_1': [2]}
    # s_r_str_set = {'2_0', '0_1', '0_0'}
    # h_tensor =torch.tensor([0])
    # r_tensor =torch.tensor([1])

    my_dict=orgin_dict.copy()#补全后的字典-无序
    #取得字典所有元素集合-求长度
    # d = {(0, 5): [1, 3, 4], (0, 1): [2], (2, 0): [4]}
    s = set()#-》原始字典所有元素
    for k, v in my_dict.items():
        # print(k)
        s.update(k)#注意：字典中添加元组时，会分别添加
        s.update(v)
    # print(s)
    orign_vocab_size=len(s)

    # Count the total number of integers in the flattened list
    # orign_vocab_size = len(flat_list)
    complet_value=[vocab_size]
    # print(my_dict)
    #(2)字典值列表补全到最大长度（补全值为vocal_size）
    # 计算所有值列表的最大长度
    # origin_max_len = max([len(v) for v in my_dict.values()])

    max_key, origin_max_len = max({k: len(v) for k, v in my_dict.items()}.items(), key=lambda x: x[1])
    print(f"原始字典self.vocab_size={orign_vocab_size}，值列表最大长度={origin_max_len},所在key={max_key},\
          要求全部键len={len(kset)}")
    # print(f"原始字典vocab_size={orign_vocab_size}，值列表最大长度={origin_max_len}")
    print(f"补全后字典vocab_size={vocab_size}，值列表最大长度={max_len}")
    # 将所有值列表的长度补到相等长度
    # print(my_dict)
    for k in kset:
        # for k1,v1 in orgin_dict.items():
        if k not in my_dict.keys():
            my_dict[k]=complet_value* (max_len)
        elif len(my_dict[k])<max_len:
            my_dict[k] = my_dict[k]+complet_value * (max_len-len(my_dict[k]))
    return my_dict


def dict_get_neigh_by_h_r(comp_dict,h_tensor,r_tensor,vocab_size,max_len):
    """功能：给定张量s,r，根据补全后的字典{（s,r）:[o]} ，取对应的o张量； \n
    优点：对不存在的(s,r)，其邻居为[vocab_size]*max_len； \n
    形式：tensor(s),tensor(r) ,{（s,r）:[]} -> tensor(o) ； \n
    如：{(0, 0): [1, 3, 4], (0, 1): [2, 5, 5], (2, 0): [4, 5, 5]} \n
        h_tensor=torch.tensor([0, 2]) \n
        r_tensor=torch.tensor([1, 3]) \n
        -》tensor([[2, 5, 5],
        [5, 5, 5]], dtype=torch.int32) \n
    参数：comp_dict（补全后的字典-无序） \n
    返回：torch.Size(len(h_tensor),max_len)
    调用：
        import dgl
        # 创建有向图
        src_list = [0, 0, 0, 0, 2]
        dst_list = [1, 2, 3, 4, 4]
        rel_list = [0, 1, 0, 0, 0]
        g = dgl.graph((src_list, dst_list))
        g.edata['rel_type'] = torch.tensor(rel_list)
        h_r_tlist_dict,key_set=dgl2dict_tuple_list(g)#->{(0, 0): [1, 3, 4], (0, 1): [2], (2, 0): [4]} \t {(0, 1), (2, 0), (0, 0)}
        # orgin_dict = {(0, 0): [1, 3, 4], (0, 1): [2]}#, (2, 0): [4]
        # s_r_str_set = {(0, 1), (2, 0), (0, 0)}
        comp_dict=dict_tuple_list_complet_bykey_value(h_r_tlist_dict,key_set,vocab_size=5,max_len=3)
        print(comp_dict)
        h_tensor=torch.tensor([0, 2])
        r_tensor=torch.tensor([1, 3])
        value_tensor,new_key=dict_get_neigh_by_h_r(comp_dict,h_tensor,r_tensor,vocab_size=5,max_len=3)
        print(value_tensor)
    """

    # 由已知取键张量：
    # 先连接(h,r): torch.tensor([0, 2])   ([1, 0])-> tensor([[0, 1],[2, 0]])
    key_tensor = torch.cat([torch.tensor(list(x)).unsqueeze(0) for x in zip(h_tensor, r_tensor)], dim=0)
    #遍历key_tensro
    key_tensor=key_tensor.tolist()

    value_list=[]
    #根据key在补全字典中取value
    new_key=[]#验证、测试集中新出现的(head,relation)键list
    for k in key_tensor:
        k=tuple(k)#[0,1]->(0,1)
        # print(k)
        if k in comp_dict:#如果键在补全字典中（训练集的肯定在）
            value_list.append(comp_dict[k])
        else:#如果键不在补全字典中（验证、测试集的不一定在）
            new_key.append(new_key)
            value_list.append([vocab_size]*max_len)#全部追加未见过
    value_tensor=torch.tensor(value_list,dtype=torch.int)#二维list-》二维tensor
    # print(value_tensor)
    return value_tensor,new_key


def dict_ele_str2int_count(orgin_dict):
    """功能：字典元素计数，str的也分隔为2个整数；
    形式：{'0_0': [1, 3, 4], '0_1': [2]}-》 5
    """
    # orgin_dict = {'0_0': [1, 3, 4], '0_1': [2]}

    # Flatten the list of keys and values into a single list of integers
    flat_list = set([int(x) for k, v in orgin_dict.items() for x in k.split('_') + v])

    # Count the total number of integers in the flattened list
    total_count = len(flat_list)
    # print(total_count)  # Output: 5
    return total_count



def dict_vlist_comple_2Embedding(d1,vocab_size,embed_size):
    """功能：字典键的自适应嵌入（结合值列表），返回嵌入结果（有序tensor和无序字典）；
    思路：(1)字典键的自适应嵌入（结合值列表）；k嵌入=k嵌入+value嵌入；
    (2)embedding的总维度+1，最高维设为全0；
    （3）字典补全（字典长度变为vocab_size）：，补全未出现的键:[vocab_size]；

    注意：embedding()调用时: 索引 must be Tensor, not int
    返回：
        embeddings(顺序同d1_comple，并不一定从0-vocab_size):tensor(vocab_size,embed_size),
        embeddings_dict:{键:tensor(embed_size)},
        d1_comple:长度=vocab_size,
        embeddings_order（有序）:tensor(vocab_size,embed_size)
    调用：
        d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
        embeddings,embeddings_dict,d1_comple,embeddings_order = dict_vlist_comple_2Embedding(d1, 4, 5)
        print(embeddings_dict)
        print(embeddings_order)
    """
    import collections
    # d1={0: [1, 2], 1: [2, 3,0],3:[0]}
    d1_comple=dict_comple_bykey(d1,vocab_size,[vocab_size])#补全字典到vocab_size长度
    # print(d1_comple)
    emb=emb_highest_dim_zero(vocab_size+1,embed_size)#增加最高维，并置0
    # # 生成包含所有索引的张量
    # indices = torch.arange(4)
    # # 将索引张量传递给嵌入层，获取所有嵌入向量
    # embeddings = emb(indices)
    # 定义一个空列表用于保存所有的嵌入向量
    embeddings = []
    embeddings_dict={}#collections.OrderedDict()没用
    #{k:计算后的嵌入表示}
    # 循环遍历字典 d1
    for k, v in d1_comple.items():
        # 获取自身的嵌入向量
        emb_k = emb(torch.tensor([k]))
        # 获取值列表中索引所对应的嵌入向量
        emb_v = emb(torch.tensor(v))
        # 将自身嵌入向量和值列表中索引所对应的嵌入向量相加
        emb_kv = torch.sum(torch.cat([emb_k, emb_v], dim=0), dim=0)
        # 将嵌入向量添加到列表中
        embeddings.append(emb_kv)
        embeddings_dict[k]=emb_kv
    #  将嵌入表示按索引有序存入
    embeddings_order=[]##list->tensor
    for i in range(vocab_size):
        embeddings_order.append(embeddings_dict[i].tolist())
    # print(embeddings_order)
    embeddings_order=torch.tensor(embeddings_order)    #list->tensor
    # print(embeddings_dict)
    # 将所有嵌入向量拼接为一个张量
    embeddings = torch.stack(embeddings)

    return embeddings,embeddings_dict,d1_comple,embeddings_order
# d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
# embeddings,embeddings_dict,d1_comple,embeddings_order = dict_vlist_comple_2Embedding(d1, 4, 5)
# print(embeddings_dict)
# print(embeddings_order)

class Dict_Embedding(nn.Module):
    """功能：字典补全到vocab_size长度，取得所有索引有序嵌入；索引嵌入=自身索引嵌入+sum(邻居索引嵌入)；
    输入：
        d1:{索引:[邻居索引]}
    返回：
        d1_comple:      补全字典长度到vocab_size,
        self.emb    ：   Embedding(vocab_size+1, embed_size)且最大索引值全为0，
        embeddings: tensor(vocab_size,embed_size)   (顺序同d1_comple，并不一定从0-vocab_size)，
        embeddings_dict:            {键:tensor(embed_size)},
        embeddings_order（有序）:       tensor(vocab_size,embed_size)，
    调用：
        d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
        dict_emb_model=Dict_Embedding(d1,4,3)
        embeddings_order=dict_emb_model.emembeddings_order
    """
    def __init__(self,d1:{},vocab_size, embed_size):
        super().__init__()

        self.d1=d1
        self.vocab_size=vocab_size
        self.embed_size=embed_size
        self.d1_comple = self.dict_comple_bykey()
        self.emb= self.emb_highest_dim_plus1_zero() #->Embedding(vocab_size+1, embed_size)
        self.embeddings, self.embeddings_dict, self.embeddings_order=self.dict_vlist_comple_2Embedding()

    def forward(self):
        pass

    def dict_comple_bykey(self):
        """功能：（1）按总索引补全字典键，补全值为索引上限+1即 [self.vocab_size]；（2）补全后字典长度=total_index
        调用：
            d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
            print(dict_comple_bykey(d1,4,[-1]))#-》{0: [1, 2], 1: [2, 3, 0], 3: [0], 2: [-1]}
        """
        # d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
        # total_index = 4

        # 补全索引键
        d1_comple=self.d1.copy()
        for i in range(self.vocab_size):
            if i not in d1_comple:
                d1_comple[i] = [self.vocab_size]

        # print(d1)  # 输出补全后的字典
        return d1_comple

    def embdding_print(self):
        import torch.nn as nn

        # # 创建一个embedding层
        # emb = nn.Embedding(5, 3)
        # 打印embedding层的形状
        print("emb.weight.shape:", self.emb.weight.shape)
        print("emb.weight.data:", self.emb.weight.data)

    def emb_highest_dim_zero(self):
        """功能：创建一个Embedding，并将emb的最高维度数据置0；
        调用：
            emb=emb_highest_dim_zero(5,3)
            print(emb(torch.LongTensor([4])))
        """
        import torch.nn as nn
        import torch

        # 创建一个embedding层
        emb = nn.Embedding(self.vocab_size, self.embed_size)

        # 将embedding向量的最高维度设置为0
        emb.weight.data[self.vocab_size - 1].zero_()  # emb.weight.data.zero_()#所有数据均置0

        # 查看emb矩阵
        input_indices = torch.LongTensor(range(self.vocab_size))
        embedded = emb(input_indices)
        # print(embedded)
        return emb

    def emb_highest_dim_plus1_zero(self):
        """功能：创建一个Embedding(self.vocab_size+1, self.embed_size)，并将emb的最高维度数据置0；
        调用：
            emb=emb_highest_dim_zero(5,3)
            print(emb(torch.LongTensor([4])))
        """

        # 创建一个embedding层
        emb = nn.Embedding(self.vocab_size+1, self.embed_size)

        # 将索引为4的embedding向量的最高维度设置为0
        emb.weight.data[self.vocab_size - 1].zero_()  # emb.weight.data.zero_()#所有数据均置0

        # # 查看emb矩阵
        # input_indices = torch.LongTensor(range(self.vocab_size))
        # embedded = emb(input_indices)
        # # print(embedded)
        return emb

    def dict_vlist_comple_2Embedding(self):
        """功能：字典键的自适应嵌入（结合值列表），返回嵌入结果（有序tensor和无序字典）；
        思路：(1)字典键的自适应嵌入（结合值列表）；k嵌入=k嵌入+value嵌入；
        (2)embedding的总维度+1，最高维设为全0；
        （3）字典补全（字典长度变为vocab_size）：，补全未出现的键:[vocab_size]；

        注意：embedding()调用时: 索引 must be Tensor, not int
        返回：
            embeddings(顺序同d1_comple，并不一定从0-vocab_size):tensor(vocab_size,embed_size),
            embeddings_dict:{键:tensor(embed_size)},
            d1_comple:长度=vocab_size,
            embeddings_order（有序）:tensor(vocab_size,embed_size)
        调用：
            d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
            dict_emb_model=Dict_Embedding(d1,4,3)
            dict_emb_model.embeddings_dict
            embeddings_order=dict_emb_model.embeddings_order
            print("embeddings_dict:",dict_emb_model.embeddings_dict)
            print("embeddings_order:",dict_emb_model.embeddings_order)
            # print(embeddings_order.shape)
        """
        import collections
        # d1={0: [1, 2], 1: [2, 3,0],3:[0]}
        # d1_comple = dict_comple_bykey(d1, vocab_size, [vocab_size])  # 补全字典到vocab_size长度
        # print(d1_comple)
        # emb = emb_highest_dim_zero(self.vocab_size + 1, self.embed_size)  # 增加最高维，并置0
        # # 生成包含所有索引的张量
        # indices = torch.arange(4)
        # # 将索引张量传递给嵌入层，获取所有嵌入向量
        # embeddings = emb(indices)
        # 定义一个空列表用于保存所有的嵌入向量
        # emb=self.emb_highest_dim_zero(self.vocab_size+1,self.embed_size)#->Embedding(vocab_size+1, embed_size)
        embeddings = []
        embeddings_dict = {}  # collections.OrderedDict()没用
        # {k:计算后的嵌入表示}
        # 循环遍历字典 d1
        for k, v in self.d1_comple.items():
            # 获取自身的嵌入向量
            emb_k = self.emb(torch.tensor([k]))
            # 获取值列表中索引所对应的嵌入向量
            emb_v = self.emb(torch.tensor(v))
            # 将自身嵌入向量和值列表中索引所对应的嵌入向量相加
            emb_kv = torch.sum(torch.cat([emb_k, emb_v], dim=0), dim=0)
            # 将嵌入向量添加到列表中
            embeddings.append(emb_kv)
            embeddings_dict[k] = emb_kv
        #  将嵌入表示按索引有序存入
        embeddings_order = []  ##list->tensor
        for i in range(self.vocab_size):
            embeddings_order.append(embeddings_dict[i].tolist())
        # print(embeddings_order)
        embeddings_order = torch.tensor(embeddings_order)  # list->tensor
        # print(embeddings_dict)
        # 将所有嵌入向量拼接为一个张量
        embeddings = torch.stack(embeddings)

        return embeddings, embeddings_dict, embeddings_order
# d1 = {0: [1, 2], 1: [2, 3, 0], 3: [0]}
# dict_emb_model=Dict_Embedding(d1,4,3)
# # print("Embedding：",emb.weight)
# embeddings_order=dict_emb_model.embeddings_order
# print("embeddings_dict:",dict_emb_model.embeddings_dict)
# print("embeddings_order:",dict_emb_model.embeddings_order)
# # print(embeddings_order.shape)


def dict_lsep_2str(d1):
    """
    功能：LSEP处理；
    思路：''写文件或print不显示，其编码为'\u2028';或将其修改为Crlf；
    调用：
        d1={1:'',2:t1,'##':t1,}
        # print(d1)
        d1,del_list=dict_lsep_2str(d1)
        print(d1,del_list)
    """
    del_list=[]
    for k,v in d1.items():
        if str(k).find('')!=-1 or str(k).find('\u2028')!=-1:
            del_list.append(k)
            # d1[k+'Crlf']=v
        elif str(v).find('')!=-1 or str(k).find('\u2028')!=-1:
            del_list.append(k)
            # d1[k] = v+ 'Crlf'
    for k in del_list:
        v=d1[k]
        if str(k).find('') != -1 or str(k).find('\u2028')!=-1:
            # t=str(k)#+'Crlf'
            d1[str(k)]=v
            # d1[k+'Crlf']=v
        elif str(v).find('') != -1 or str(k).find('\u2028')!=-1:
            # t = str(v) #+ 'Crlf'
            d1[k]=str(v)
    return d1,del_list


def dict_key_minus_2set(d1,d2)->{}:
    """
    功能：d1.keys()-d2.keys()->{}
    形式：{k1:v},{k2:v}->set()
    调用：
    d1={'025':0,'35':1}
    d2={'025':0}
    set1=dict_key_minus_2set(d1,d2)
    print(set1)
    """
    set1=set()
    for k,v in d1.items():
        set1.add(k)
    for k,v in d2.items():
        set1.remove(k)
    return set1


def k2v(id, dictlist: {}) -> list:
    """
    功能：由k取v的[str]
    :param id: id=tensor([2,1,0])#一维张量
    :param dictlist:{0: ['say hello to'], 1: ['world'], 2: ['!']}

    :return:
        list：索引对应字典值    ['world', 'you', 'say hello to']
    调用：
        id=tensor([2,1,0])
        dlist_str=ddict(list)#字典-值列表形式
        dlist_str[0].append("say hello to")
        dlist_str[1].append("world")
        dlist_str[2].append("!")
        dlist=dict(dlist)
        k2v(id,dlist_str)

    """
    d_text = []
    for i in list(id):
        d_text.append(dictlist[int(i)][0])  # 取列表首元
    print(d_text)  # ['!', 'world', 'say hello to']
    return d_text


def set_replace(set1,oldstr='.',newstr='_')->set:
    """功能：替换集合元素中的'.'为'_'
    调用：
    set1={'a.',12}
    set2=set_replace(set1)
    print(set2)
    """
    set2=set()
    for i in set1:
        if type(i)==str:
            set2.add(i.replace(oldstr,newstr))
        else:
            set2.add(i)
    return set2


def set2txt(my_set,output_file):
    """调用：
    my_set = {1, 2, 3, 4, 5}
    set2txt(my_set,'output.txt')"""
    # 打开文件并写入数据
    with open(output_file, 'w') as file:
        for item in my_set:
            file.write(str(item) + '\n')
        print(f"{output_file}生成成功！")
    # 关闭文件
    file.close()

def txt2set(output_file):
    """将txt整行放入集合；"""
    # 打开文件并读取数据
    with open(output_file, 'r') as file:
        lines = file.readlines()
    my_set = set()
    # 遍历行并添加到集合
    for line in lines:
        # 去除行末尾的换行符
        line = line.strip()
        # 添加到集合
        my_set.add(line)

    file.close()
    return my_set


def txt2set_by_col_index(intput_file,col_index,sep='\t'):
    """将txt指定列放入集合；
    调用：
    set1=txt2set_by_col_index("dict.txt",1)
    print(set1)
    """
    # 打开文件并逐行读取内容
    with open(intput_file, 'r',encoding='utf-8') as file:
        lines = file.readlines()

    # 创建一个空集合
    column_data_set = set()

    # 遍历每一行，提取第2列的数据并添加到集合中
    for line in lines:
        columns = line.strip().split(sep)  # 使用空格分割每一行的内容
        column_data_set.add(columns[col_index])  # 提取第2列的数据并添加到集合中

    # 打印集合中的数据
    # print(column_data)
    return column_data_set


def txt_col_find_not_int_set2(intput_file,col_index,set1,sep='\t'):
    """将txt指定列不在集合中的元素写入txt；\n
    调用：\n
    set1=txt2set_by_col_index("dict.txt",1)
    print(set1)
    not_in_set_data=txt_col_find_not_int_set("dict1.txt", 1,set1)
    print(f"not_in_set_data,len={len(not_in_set_data)},{not_in_set_data}")
    """
    # 打开文件并逐行读取内容
    with open(intput_file, 'r',encoding='utf-8') as file:
        lines = file.readlines()

    # 创建一个空集合
    column_data = set()

    not_in_set_data=[]#[str],str不加换行符
    # 将不在集合数据写入[]
    for line in lines:
        columns = line.strip().split(sep)  # 使用空格分割每一行的内容
        col_data=columns[col_index]
        if col_data not in set1:
            not_in_set_data.append(col_data)

    # 打印集合中的数据
    # print(column_data)
    return not_in_set_data


def txt_file2_col_find_not_int_file1_col(file1,col1_index,file2,col2_index,out_file,lower=1,sep='\t'):
    """整列判断：file1为基准(取指定列集合)，找file2指定列不在基准列中-》写入文件（默认均转小写）；\n
    参数：lower表示均转为小写判断；
    调用：\n
    txt_file2_col_find_not_int_file1_col("dict.txt",1,"dict1.txt",1,"dict_not_in.txt")
    """
    #1.取文件1指定列的集合
    with open(file1, 'r',encoding='utf-8') as file:
        lines = file.readlines()

    # 创建一个空集合
    column_data_set = set()

    # 遍历每一行，提取第2列的数据并添加到集合中
    for line in lines:
        columns = line.strip().split(sep)  # 使用空格分割每一行的内容
        col1_val=str(columns[col1_index])
        if lower:
            col1_val=col1_val.lower()
        column_data_set.add(col1_val)  # 提取第2列的数据并添加到集合中

    # 2.取file2指定列，并判断
    with open(file2, 'r',encoding='utf-8') as file:
        lines = file.readlines()

    not_in_set_data=[]#[str],str不加换行符
    # 将不在集合数据写入[]
    for line in lines:
        columns = line.strip().split(sep)  # 使用空格分割每一行的内容
        col2_data=str(columns[col2_index])
        if lower:
            col2_data=col2_data.lower()
        if col2_data not in column_data_set:
            not_in_set_data.append(col2_data)

    # 3.[]写入文件
    with open(out_file, "w", encoding='utf-8') as file:
        # 遍历列表中的每个元素，并将其写入文件中
        for item in not_in_set_data:
            item = str(item).strip()  # 去空
            file.write("%s\n" % item)
        print(f"{out_file}写入成功")
# txt_file2_col_find_not_int_file1_col("dict.txt",1,"dict1.txt",1,"dict_not_in.txt")

def txt_file2_col_find_not_int_file1_col_by_word(file1,col1_index,file2,col2_index,out_file,lower=1,sep='\t'):
    """判断：file1为基准(取指定列集合)，找file2指定列（空格分词后）不在基准列中-》写入文件（默认均转小写）；\n
    形式：file1中为单词列；file2中为句子列-》不在file1的单词列
    参数：lower表示均转为小写判断；
    调用：\n
    txt_file2_col_find_not_int_file1_col_by_word("dict.txt",1,"dict1.txt",1,"dict_not_in.txt")
    """
    #1.取文件1指定列的集合
    with open(file1, 'r',encoding='utf-8') as file:
        lines = file.readlines()

    # 创建一个空集合
    column_data_set = set()

    # 遍历每一行，提取第2列的数据并添加到集合中
    for line in lines:
        columns = line.strip().split(sep)  # 使用空格分割每一行的内容
        col1_val=str(columns[col1_index])
        if lower:
            col1_val=col1_val.lower()
        column_data_set.add(col1_val)  # 提取第2列的数据并添加到集合中

    # 2.取file2指定列-分词后（按空格）放入集合，并判断
    column_word_set2 = set()
    with open(file2, 'r',encoding='utf-8') as file:
        lines = file.readlines()

    # 将不在集合数据写入[]
    for line in lines:
        columns = line.strip().split(sep)  # 使用空格分割每一行的内容
        col2_data=str(columns[col2_index])
        col2_words=col2_data.strip().split(' ')#按空格分词
        for col_word in col2_words:
            if lower:
                col_word=col_word.lower()
            column_word_set2.add(col_word)
    #3.在集合2不在集合1中的-
    set2_not_in_set1 = column_word_set2.difference(column_data_set)

    # 3.set写入文件
    with open(out_file, "w", encoding='utf-8') as file:
        # 遍历列表中的每个元素，并将其写入文件中
        for item in set2_not_in_set1:
            item = str(item).strip()  # 去空
            file.write("%s\n" % item)
        print(f"{out_file}写入成功")
# txt_file2_col_find_not_int_file1_col_by_word("dict.txt",1,"dict1.txt",1,"dict_not_in.txt")

def dict_get_first_kv(d1):
    """取字典的首元->(first_key,first_value)"""
    # d1={1:0,2:1,3:2}
    first_key=next(iter(d1))
    first_value=d1[first_key]
    # print(first_key,first_value)
    return (first_key,first_value)


def dict_sum_v_by_k(d1,k2,v2):
    """更新dict：存在则加上v，不存在则加入；
    调用：
    d1={1:np.array([0,1]),2:np.array([0,1])}
    k2=1
    v2=np.array([0,1])
    d1=dict_sum_v_by_k(d1,k2,v2)#->{1: array([0, 2], dtype=int64), 2: array([0, 1], dtype=int64)}
    """
    if k2 in d1.keys():
        d1[k2] = d1[k2] + v2
    else:
        d1[k2] = v2
    # print(d1)
    return d1


def dict2str(my_dict):
    """
    功能：将dict转换为"row[k]=v and"形式
    返回：row['key1']=value1 and row['key2']=value2 and row['key3']=value3
    调用：
        my_dict = {"key1": "value1", "key2": "value2", "key3": "value3"}
        my_str=dict2str(my_dict)
        print(my_str)
    """

    # 使用列表推导式循环调用字典的键值对，并连接成字符串
    my_str = " and ".join([f"row[{k}】=={v}" for k, v in my_dict.items()])
    return my_str


def dict_traverse(my_dict):
    """
    功能：循环遍历字典中的所有键值对是否相等；又有不满足的则返回0
    调用：
        my_dict = {"key1": "value1", "key2": "value2", "key3": "value3"}
        flag=dict_traverse(my_dict)
        print(flag)
    """
    flag=1
    for key, value in my_dict.items():
        # 如果键和值不相等，则打印一条错误消息并退出循环
        if key != value:
            flag=0
            break

    return flag


def dict_equal(dict1,dict2):
    """功能： 判断2个字典是否相等（方式：将字典转换为元组列表进行比较，）
    优点：和字典顺序无关；
    调用：
    dict1 = {'a': 1, 'b': 2, 'c': 3}
    dict2 = {'b': 2, 'c': 2, 'a': 1}
    flag=dict_equal(dict1,dict2)
    """
    if sorted(dict1.items()) == sorted(dict2.items()):
        return True
    else:
        return False


# examples_len_set = examples_len_set-subset
# print(subset,examples_len_set)

# t1=np.array(tensor([-0.0363, -0.1497,  0.0588,  0.1964, -0.2063]))
# t1=tensor([[-0.0363, -0.1497,  0.0588,  0.1964, -0.2063]])#torch.Size([1, 5])
# print(t1.shape)
# print(dictensor2tensor(d1).shape)#torch.Size([1, 5])->(2,5)
# t1=np.array(tensor([0,1]))
# d1={1:t1,2:t1}
#
# # print(d1[0])
# d2={5:4}
# print(dict_update_by_dict2(d1,d2))
# print(d1.copy())
# print(d1.get(3,3))
# print(d1)
# d1={0: [3,2,1], 1:[0,1,2]}
# t1=tensor([[-0.0363, -0.1497,  0.0588,  0.1964, -0.2063]])
# d1={1:t1}
# set1={'a.',12}
# k1, v1 = dictkv2tensor(d1)
# print(k1.shape,k1[:2],len(k1))
# pred_index={0: [3,2,1], 1:[0,1,2]}#->[0.0, 0.5, 0.5],[0, 1, 1]/2
# hitn_list,hitn_num_list,l=dict_hitn_acc_list(pred_index)
# print(f"pred_index的hitn_list：{hitn_list},{hitn_num_list}/{l}")

# key_set=set(range(10))
# print(key_set)

# txt2dict()

"""
功能：将yaml文件转换为列表字典；
提取层级：1级：'paths'层级；2级：'get'方法；3级：'description'字段；
#形式：.yaml->[k：v]
yaml文件形式：
paths:
  /access_group_caches:
    get:
      description: 列表
"""
def yaml2ListDict():
    # yaml_file = './data/swagger_compute.yaml'
    yaml_file = 'D:\ProjectWorkspace\GoProject\yunionio\skycloud\docs\swagger\swagger_yunionconf.yaml'

    # 读取 YAML 文件
    with open(yaml_file, 'r', encoding='utf-8') as file:
        # 使用 yaml.safe_load() 函数将 YAML 内容转换为字典
        data = yaml.safe_load(file)

        # 获取 'paths' 层级的内容
        paths = data.get('paths', {})

        # 初始化一个列表来存储提取的数据
        extracted_data = []

        # 遍历 'paths' 层级下的所有条目
        for path, methods in paths.items():
            # 遍历每个路径下的方法（如 'get', 'post' 等）
            for method, details in methods.items():
                # 获取 'description' 字段的内容
                description = details.get('description', 'No description available')
                # 将提取的数据添加到列表中
                extracted_data.append({
                    'Paths': path,
                    'Method': method,
                    'Description': description
                })

        print("extracted_data:len={}\n".format(len(extracted_data)))

"""
功能：将列表字典转换为excel文件；
#形式：[k：v]->.xlsx
#pip install openpyxl
"""
def listDict2Excel():
    df = pd.DataFrame(extracted_data)
    # 将 DataFrame 写入 Excel 文件
    excel_file = 'apifox_export.xlsx'
    df.to_excel(excel_file, index=False, sheet_name='API Documentation')

    print(f'数据已导出到 {excel_file}')


"""
功能：将yaml文件转换为excel文件；提取一级字符；
提取层级：1级：'paths'层级；2级：'get'方法；3级：'description'字段；
形式：.yaml->[k：v]->.xlsx

"""
def yaml2Excel():
    # yaml_file = './data/swagger_compute.yaml'
    yaml_file = 'D:\ProjectWorkspace\GoProject\yunionio\skycloud\docs\swagger\swagger_yunionconf.yaml'
    
    # 读取 YAML 文件
    with open(yaml_file, 'r', encoding='utf-8') as file:
        # 使用 yaml.safe_load() 函数将 YAML 内容转换为字典
        data = yaml.safe_load(file)

        # 获取 'paths' 层级的内容
        paths = data.get('paths', {})
    
        # 初始化一个列表来存储提取的数据
        extracted_data = []
    
        # 遍历 'paths' 层级下的所有条目
        for path, methods in paths.items():
            # 遍历每个路径下的方法（如 'get', 'post' 等）
            for method, details in methods.items():
                # 获取 'description' 字段的内容
                description = details.get('description', 'No description available')
                # 将提取的数据添加到列表中
                extracted_data.append({
                    'Paths': path,
                    'Method': method,
                    'Description': description
                })
    
        print("extracted_data:len={}\n".format(len(extracted_data)))
    
    
    #形式：[k：v]->.xlsx
    #pip install openpyxl
    # 将提取的数据转换为 DataFrame
    df = pd.DataFrame(extracted_data)
    
    # 将 DataFrame 写入 Excel 文件
    excel_file = 'apifox_export.xlsx'
    df.to_excel(excel_file, index=False, sheet_name='API Documentation')
    
    print(f'数据已导出到 {excel_file}')